package com.tuuzed.android.qrcode;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.ColorInt;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.tuuzed.android.qrcode.internal.BitmapUtil;
import com.tuuzed.android.qrcode.internal.PhotoUtil;
import com.tuuzed.android.qrcode.internal.ProviderUriUtil;
import com.tuuzed.android.qrcode.internal.decode.BitmapDecoder;
import com.tuuzed.android.util.LogUtil;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class QRCodeUtil {
    private static final String TAG = "QRCodeUtil";

    public static void choiceQRCodePic(@NonNull Activity host, @NonNull CharSequence chooserTitle, int requestCode) {
        PhotoUtil.choicePic(host, chooserTitle, requestCode);
    }

    public static void choiceQRCodePic(@NonNull android.app.Fragment host, @NonNull CharSequence chooserTitle, int requestCode) {
        PhotoUtil.choicePic(host, chooserTitle, requestCode);
    }

    public static void choiceQRCodePic(@NonNull android.support.v4.app.Fragment host, @NonNull CharSequence chooserTitle, int requestCode) {
        PhotoUtil.choicePic(host, chooserTitle, requestCode);
    }

    public static void handleChoiceQRCodePic(@NonNull Context context, @NonNull Intent data,
                                             @NonNull OnResultCallback callback) {
        // 获取选中图片的路径
        Uri uri = data.getData();
        if (uri == null) {
            callback.onResult(null);
            return;
        }
        final String photoPath = ProviderUriUtil.getRealPathFromUri(context, uri);
        LogUtil.d(TAG, "onActivityResult: photoPath = " + photoPath);
        if (photoPath == null) {
            callback.onResult(null);
        }
        Bitmap src = BitmapUtil.getCompressedBitmap(photoPath);
        QRCodeUtil.decodeQRCode(src, callback);
    }

    @NonNull
    public static Bitmap encodeQRCode(@NonNull String content) throws WriterException {
        return encodeQRCode(content, 480, Charset.forName("utf-8"), Color.BLACK);
    }

    @NonNull
    public static Bitmap encodeQRCode(@NonNull String content, int widthAndHeight,
                                      @NonNull Charset charset, @ColorInt int color) throws WriterException {
        Hashtable<EncodeHintType, String> hints = new Hashtable<>();
        hints.put(EncodeHintType.CHARACTER_SET, charset.name());
        // 生成二维矩阵,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败
        BitMatrix matrix = new MultiFormatWriter()
                .encode(content, BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight, hints);
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        // 二维矩阵转为一维像素数组,也就是一直横着排了
        int[] pixels = new int[width * height];
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (matrix.get(x, y)) {
                    pixels[y * width + x] = color;
                }
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        // 通过像素数组生成bitmap,具体参考api
        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
        return bitmap;
    }

    @NonNull
    public static Bitmap encodeQRCodeWithLogo(@NonNull String content, @NonNull Bitmap logo) throws WriterException {
        return encodeQRCodeWithLogo(content, 480, Charset.forName("utf-8"), Color.BLACK, logo);
    }

    @NonNull
    public static Bitmap encodeQRCodeWithLogo(@NonNull String content, int widthAndHeight,
                                              @NonNull Charset charset,
                                              @ColorInt int color, @NonNull Bitmap logo) throws WriterException {
        Bitmap scaleLogo = scaleLogo(logo, widthAndHeight);
        int scaleWidth, scaleHeight;
        scaleWidth = scaleLogo.getWidth();
        scaleHeight = scaleLogo.getHeight();
        int offsetX, offsetY;
        offsetX = offsetY = (widthAndHeight - scaleWidth) / 2;
        Map<EncodeHintType, Object> hints = new HashMap<>(3);
        hints.put(EncodeHintType.CHARACTER_SET, charset.name());
        //容错级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        //设置空白边距的宽度
        hints.put(EncodeHintType.MARGIN, 10);
        QRCodeWriter QRCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = QRCodeWriter.encode(content,
                BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight, hints);
        int[] pixels = new int[widthAndHeight * widthAndHeight];
        for (int y = 0; y < widthAndHeight; y++) {
            for (int x = 0; x < widthAndHeight; x++) {
                if (x >= offsetX && x < offsetX + scaleWidth && y >= offsetY && y < offsetY + scaleHeight) {
                    int pixel = scaleLogo.getPixel(x - offsetX, y - offsetY);
                    if (pixel == 0) {
                        if (bitMatrix.get(x, y)) {
                            pixel = color;
                        } else {
                            pixel = 0xffffffff;
                        }
                    }
                    pixels[y * widthAndHeight + x] = pixel;
                } else {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * widthAndHeight + x] = color;
                    } else {
                        pixels[y * widthAndHeight + x] = 0xffffffff;
                    }
                }
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(widthAndHeight, widthAndHeight, Bitmap.Config.ARGB_8888);
        bitmap.setPixels(pixels, 0, widthAndHeight, 0, 0, widthAndHeight, widthAndHeight);
        return bitmap;
    }


    @MainThread
    public static void decodeQRCode(@NonNull final Bitmap src, @NonNull final OnResultCallback callback) {
        new AsyncTask<Void, Void, Result>() {

            @Override
            protected Result doInBackground(Void... voids) {
                try {
                    return BitmapDecoder.getDefault().getResult(src);
                } catch (NotFoundException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Result result) {
                callback.onResult(result);
            }
        }.execute();
    }

    @MainThread
    public static void decodeQRCode(@NonNull final BinaryBitmap src, @NonNull final OnResultCallback callback) {
        new AsyncTask<Void, Void, Result>() {

            @Override
            protected Result doInBackground(Void... voids) {
                try {
                    return BitmapDecoder.getDefault().getResult(src);
                } catch (NotFoundException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Result result) {
                callback.onResult(result);
            }
        }.execute();
    }

    private static Bitmap scaleLogo(@NonNull Bitmap logo, int widthAndHeight) {
        Matrix matrix = new Matrix();
        final float scaleFactor = widthAndHeight * 1.0f / 8 / logo.getWidth();
        matrix.postScale(scaleFactor, scaleFactor);
        return Bitmap.createBitmap(logo, 0, 0, logo.getWidth(), logo.getHeight(), matrix, true);
    }

}
